//Recorder vars
boolean recording = true;
boolean playingBack = false;

String[] debugValue = new String[10000];
int debugVC = 0;

int[] rDownEvents = new int[1000];
int[] gDownEvents = new int[1000];
int[] bDownEvents = new int[1000];
int[] rightDownEvents = new int[1000];
int[] leftDownEvents = new int[1000];
int[] rUpEvents = new int[1000];
int[] gUpEvents = new int[1000];
int[] bUpEvents = new int[1000];
int[] rightUpEvents = new int[1000];
int[] leftUpEvents = new int[1000];

int rDownCount = 0;
int gDownCount = 0;
int bDownCount = 0;
int rightDownCount = 0;
int leftDownCount = 0;
int rUpCount = 0;
int gUpCount = 0;
int bUpCount = 0;
int rightUpCount = 0;
int leftUpCount = 0;

int rDownPlay = 0;
int gDownPlay = 0;
int bDownPlay = 0;
int rightDownPlay = 0;
int leftDownPlay = 0;
int rUpPlay = 0;
int gUpPlay = 0;
int bUpPlay = 0;
int rightUpPlay = 0;
int leftUpPlay = 0;

void printRecorded(){
  for (int i=0; i<rDownCount; i++){
    println("Red down at "+rDownEvents[i]);
  }
  for (int i=0; i<rUpCount; i++){
    println("Red up at "+rUpEvents[i]);
  }
}

void loadKeyStates(){
//  stepCount -= 1;
  if (stepCount == rDownEvents[rDownPlay]){
    if (!keyState['r']){rePose = true;}
    keyState['r'] = true;
    if (rDownPlay < rDownCount) rDownPlay++;
 //   println(stepCount);
  }
  if (stepCount == rUpEvents[rUpPlay]){
    if (keyState['r']){rePose = true;}
    keyState['r'] = false;
    if (rUpPlay < rUpCount) rUpPlay++;
//    println(stepCount);
  }    
  if (stepCount == gDownEvents[gDownPlay]){
    if (!keyState['g']){rePose = true;}
    keyState['g'] = true;
    if (gDownPlay < gDownCount) gDownPlay++;
  }
  if (stepCount == gUpEvents[gUpPlay]){
    if (keyState['g']){rePose = true;}
    keyState['g'] = false;
    if (gUpPlay < gUpCount) gUpPlay++;
  }      
  if (stepCount == bDownEvents[bDownPlay]){
    if (!keyState['b']){rePose = true;}
    keyState['b'] = true;
    if (bDownPlay < bDownCount) bDownPlay++;
  }
  if (stepCount == bUpEvents[bUpPlay]){
    if (keyState['b']){rePose = true;}
    keyState['b'] = false;
    if (bUpPlay < bUpCount) bUpPlay++;
  }    
  if (stepCount == rightDownEvents[rightDownPlay]){
    keyRight = true;
    if (rightDownPlay < rightDownCount) rightDownPlay++;
  }
  if (stepCount == rightUpEvents[rightUpPlay]){
    keyRight = false;
    if (rightUpPlay < rightUpCount) rightUpPlay++;
  }      
  if (stepCount == leftDownEvents[leftDownPlay]){
    keyLeft = true;
    if (leftDownPlay < leftDownCount) leftDownPlay++;
  }
  if (stepCount == leftUpEvents[leftUpPlay]){
    keyLeft = false;
    if (leftUpPlay < leftUpCount) leftUpPlay++;
  }
//  stepCount += 1;  
}

void keyPressed(){
//  println(stepCount);
  if ((key == ' ')){
    keyState[' '] = true;
  }
  if (playingBack) return;
  if (key == CODED) {
    if (keyCode == RIGHT) {
      keyRight = true;
      rightDownEvents[rightDownCount] = stepCount;
      rightDownCount++;
    } else if (keyCode == LEFT) {
      keyLeft = true;
      leftDownEvents[leftDownCount] = stepCount;
      leftDownCount++;    } 
  }

  if ((key == 'r' || key == 'R')){ 
    if (!keyState['r']){
      rePose = true;
    }
    keyState['r'] = true;
    rDownEvents[rDownCount] = stepCount;
    rDownCount++;  
//    println(rDownCount);
  } 

  if ((key == 'g' || key == 'G')){ 
    if (!keyState['g']){
      rePose = true;
    }
    keyState['g'] = true;
      gDownEvents[gDownCount] = stepCount;
      gDownCount++;  
  } 

  if ((key == 'b' || key == 'B')){ 
    if (!keyState['b']){
      rePose = true;
    }
    keyState['b'] = true;
      bDownEvents[bDownCount] = stepCount;
      bDownCount++;  
  } 

  if ((key == 'd' || key == 'D')){
    keyState['d'] = true;
  }
}

void keyReleased(){
  if ((key == ' ')){
    keyState[' '] = false;
  }
  if (playingBack) return;
  if (key == CODED) {
    if (keyCode == RIGHT) {
      keyRight = false;
      rightUpEvents[rightUpCount] = stepCount;
      rightUpCount++;
    } else if (keyCode == LEFT) {
      keyLeft = false;
      leftUpEvents[leftUpCount] = stepCount;
      leftUpCount++;
    } 
  }

  if ((key == 'r' || key == 'R')){ 
    if (keyState['r']){
      rePose = true;
    }
    keyState['r'] = false;
    rUpEvents[rUpCount] = stepCount;
    rUpCount++;
  }

  if ((key == 'g' || key == 'G')){ 
    if (keyState['g']){
      rePose = true;
    }
    keyState['g'] = false;
    gUpEvents[gUpCount] = stepCount;
    gUpCount++;
  }    
  if ((key == 'b' || key == 'B')){ 
    if (keyState['b']){
      rePose = true;
    }
    keyState['b'] = false;
    bUpEvents[bUpCount] = stepCount;
    bUpCount++;
  }
  if ((key == 'd' || key == 'D')){
    keyState['d'] = false;
  }
  
}

//OPT: all of these checks ignore binning (which, if I recall, isn't set up yet for colored struts) - this is a real performance drain [FIXED]
void keyCheck(){
//boolean r = keyState['r'];
  if (rePose){ 
    
//    BUGFIX: //some events are being double-recorded, which means they are not being picked off during the playback - fix this either at record or playback stage, probably playback is safer
/*    
    println(""+myPlayer.particle[2].position.x+keyState['r']+keyState['g']+keyState['b']+keyLeft+keyRight);
    if (recording) debugValue[debugVC] = ""+myPlayer.particle[2].position.x+keyState['r']+keyState['g']+keyState['b']+keyLeft+keyRight;
    if ( playingBack && !(debugValue[debugVC].equals(""+myPlayer.particle[2].position.x+keyState['r']+keyState['g']+keyState['b']+keyLeft+keyRight))) {
      println("Problem, other one equaled "+debugValue[debugVC]+" at step "+stepCount); 
      println("Last recorded events: "+rDownEvents[rDownPlay-1]+" "+rUpEvents[rUpPlay-1]+" "+gDownEvents[gDownPlay-1]+" "+gUpEvents[gUpPlay-1]+" "+bDownEvents[bDownPlay-1]+" "+bUpEvents[bUpPlay-1]);
      println("Next recorded events: "+rDownEvents[rDownPlay]+" "+rUpEvents[rUpPlay]+" "+gDownEvents[gDownPlay]+" "+gUpEvents[gUpPlay]+" "+bDownEvents[bDownPlay]+" "+bUpEvents[bUpPlay]);
      //print("Red: ");print(rDownEvents);
      //print("Green: ");print(gDownEvents);
      //print("Blue: ");print(bDownEvents);
      exit();
      bgcolor = color(100,100,100);
    }
    debugVC++;*/
    resetPose(keyState['r'], keyState['g'], keyState['b']); 
  }

  Vector3d playerCenter = new Vector3d(myPlayer.getParticle(0).position);
//  SolidWall2d[] collidingWalls = mySpatialPartition.getWallsInRange(playerCenter.x-100,playerCenter.y-100,playerCenter.x+100,playerCenter.y+100);
  Strut[] collidingStruts = mySpatialPartition.getStrutsInRange(playerCenter.x-100,playerCenter.y-100,playerCenter.x+100,playerCenter.y+100);
  
  int rNum = 0; int gNum = 0; int bNum = 0;
  for (int m=0; m<collidingStruts.length; m++){
    int mySCol = collidingStruts[m].getStrutColor();
    if (mySCol == REDINDEX) {rNum++;}
    else if (mySCol == GREENINDEX) {gNum++;}
    else if (mySCol == BLUEINDEX) {bNum++;}
//    else if (mySCol == 0) {aNum++;}
  }        
//  println(rNum+"; "+gNum+"; "+bNum);
  
  Strut[] aredStruts = new Strut[rNum];
  Strut[] agreenStruts = new Strut[gNum];
  Strut[] ablueStruts = new Strut[bNum];
//  Strut[] aalphaStruts = new Strut[aNum];
  
  rNum = 0; gNum = 0; bNum = 0; //aNum = 0;

  for (int m=0; m<collidingStruts.length; m++){
    int mySCol = collidingStruts[m].getStrutColor();
    if (mySCol == REDINDEX) {aredStruts[rNum] = collidingStruts[m]; rNum++;}
    else if (mySCol == GREENINDEX) {agreenStruts[gNum] = collidingStruts[m]; gNum++;}
    else if (mySCol == BLUEINDEX) {ablueStruts[bNum] = collidingStruts[m]; bNum++;}
//    else if (mySCol == 0) {aalphaStruts[aNum] = collidingStruts[m]; aNum++}
  }        
  
/*  //Handle alpha (collide with all) struts
  int aStruts = alphaDStruts.size();
  for (int i=0; i<aalphaStruts.length; i++){
    handleStrutAndParticle(aalphaStruts[i].pA,aalphaStruts[i].pB,myPlayer.getParticle(REDINDEX),aalphaStruts[i]);
    handleStrutAndParticle(aalphaStruts[i].pA,aalphaStruts[i].pB,myPlayer.getParticle(GREENINDEX),aalphaStruts[i]);
    handleStrutAndParticle(aalphaStruts[i].pA,aalphaStruts[i].pB,myPlayer.getParticle(BLUEINDEX),aalphaStruts[i]);
  }
*/
//if (keyState['r']!=r) println("Key doesn't match");
  if (keyState['r']){
    if (!redGrabbing){
      int numStruts = redDStruts.size();
      for (int i=0; i<aredStruts.length; i++){
        handleStrutAndParticle(aredStruts[i].pA,aredStruts[i].pB,myPlayer.getParticle(REDINDEX),aredStruts[i]);
      }
      if (redDStruts.size()>numStruts){
        redGrabbing = true;
      }
    }
  }
  else{
    redDStruts.clear(); 
    redGrabbing = false;
    if (rnodrawStrut != null) {rnodrawStrut.setDraw(true); rnodrawStrut.setApply(true);}
    rnodrawStrut = null;
  }
  if (keyState['g']){
    if (!greenGrabbing){
      int numStruts = greenDStruts.size();
      for (int i=0; i<agreenStruts.length; i++){
        handleStrutAndParticle(agreenStruts[i].pA,agreenStruts[i].pB,myPlayer.getParticle(GREENINDEX),agreenStruts[i]);
      }
      if (greenDStruts.size()>numStruts){
        greenGrabbing = true;
      }
    }
  }
  else{
    greenDStruts.clear(); 
    greenGrabbing = false;
    if (gnodrawStrut != null) {gnodrawStrut.setDraw(true); gnodrawStrut.setApply(true);}
    gnodrawStrut = null;
  }
  if (keyState['b']){
    if (!blueGrabbing){
      int numStruts = blueDStruts.size();
      for (int i=0; i<ablueStruts.length; i++){
        handleStrutAndParticle(ablueStruts[i].pA,ablueStruts[i].pB,myPlayer.getParticle(BLUEINDEX),ablueStruts[i]);
      }
      if (blueDStruts.size()>numStruts){
        blueGrabbing = true;
      }
    }
  }
  else{
    blueDStruts.clear(); 
    blueGrabbing = false;
    if (bnodrawStrut != null) {bnodrawStrut.setDraw(true); bnodrawStrut.setApply(true);}
    bnodrawStrut = null;
  }
//  rePose = false;
}


void checkInversion(){
  Vector3d v1 = myPlayer.getParticle(REDINDEX).position.directionTo(myPlayer.getParticle(GREENINDEX).position);
  Vector3d v2 = myPlayer.getParticle(REDINDEX).position.directionTo(myPlayer.getParticle(BLUEINDEX).position);
  float cross = v1.cross(v2).z;
  if (cross > 0){ invertedRGB = false; }
  else{ invertedRGB = true; }
}

void clickHandler(){
  //OPT: there's a lot of temporary object creation here, this could be a major drain on the processor
  checkInversion();
  Vector3d mouseVec = new Vector3d(mouseX-cameraX, mouseY-cameraY, 0);
  Vector3d displacement = mouseVec.minus(myPlayer.getParticle(0).position);
  mouseVec.set(pmouseX-cameraX,pmouseY-cameraY, 0);
  Vector3d oldDisplacement = mouseVec.minus(myPlayer.getParticle(0).position);
  Vector3d change = displacement.minus(oldDisplacement);
  float spinStrength = -mouseSpinStrength*displacement.cross(change).z*.001;
  if (keyLeft) {spinStrength = maxAbsSpin*keySpinFactor; keySpinFactor = 1.0*keySpinAccel + keySpinFactor*(1.0-keySpinAccel);}
  else if (keyRight) {spinStrength = -maxAbsSpin*keySpinFactor; keySpinFactor = 1.0*keySpinAccel + keySpinFactor*(1.0-keySpinAccel);}
  else keySpinFactor = origKeySpinFactor;

  if (abs(spinStrength) > maxAbsSpin){
    spinStrength *= maxAbsSpin/abs(spinStrength);
  }
  mouseForce = spinStrength;
  smoothedMouseForce = smoothedMouseForce*.93 + mouseForce * .003;
  if (invertedRGB) { spinStrength *= -1.0; }
  float spinSign = (spinStrength > 0.0) ? 2*stepsPerFrame:-2*stepsPerFrame;
//  Vector3d currForce = myPlayer.getParticle(REDINDEX).position.directionTo(myPlayer.getParticle(BLUEINDEX).position).times(spinStrength);
  float myA = 255.0 * abs(spinStrength / maxAbsSpin) + 5;
  Vector3d currForce = myPlayer.getParticle(GREENINDEX).position.minus(myPlayer.getParticle(BLUEINDEX).position).normalized().times(-spinStrength);
  myPlayer.addForce(currForce,REDINDEX);
  if(spinBurst) burstFXParticles(1,myPlayer.getParticle(REDINDEX).position,currForce.times(-spinSign/spinStrength),myPlayer.getParticle(REDINDEX).myColor,1.9,myA);
//  currForce = myPlayer.getParticle(GREENINDEX).position.directionTo(myPlayer.getParticle(REDINDEX).position).times(spinStrength);
  currForce = myPlayer.getParticle(BLUEINDEX).position.minus(myPlayer.getParticle(REDINDEX).position).normalized().times(-spinStrength);
  myPlayer.addForce(currForce,GREENINDEX);
  if(spinBurst) burstFXParticles(1,myPlayer.getParticle(GREENINDEX).position,currForce.times(-spinSign/spinStrength),myPlayer.getParticle(GREENINDEX).myColor,1.9,myA);
//  currForce = myPlayer.getParticle(BLUEINDEX).position.directionTo(myPlayer.getParticle(GREENINDEX).position).times(spinStrength);
  currForce = myPlayer.getParticle(REDINDEX).position.minus(myPlayer.getParticle(GREENINDEX).position).normalized().times(-spinStrength);
  myPlayer.addForce(currForce,BLUEINDEX);
  if(spinBurst) burstFXParticles(1,myPlayer.getParticle(BLUEINDEX).position,currForce.times(-spinSign/spinStrength),myPlayer.getParticle(BLUEINDEX).myColor,1.9,myA);
  //  particleShot(myPlayer.getParticle(REDINDEX).position, 
  
//  burstFXParticles(,myPlayer.getParticle(REDINDEX).position,myPlayer.getParticle(REDINDEX).position.minus(myPlayer.getParticle(REDINDEX).positionLast),myPlayer.getParticle(REDINDEX).myColor,1.0);
  
}
